package com.jinghangzz.shop.goods.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Callable;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jinghangzz.shop.common.service.impl.BaseServiceImpl;
import com.jinghangzz.shop.common.util.ConstatFinalUtil;
import com.jinghangzz.shop.common.util.ExecutorUtil;
import com.jinghangzz.shop.common.util.PageInfoUtil;
import com.jinghangzz.shop.common.util.SpiderUtil;
import com.jinghangzz.shop.goods.pojo.AGoods;
import com.jinghangzz.shop.goods.pojo.AGoodsCate;
import com.jinghangzz.shop.goods.service.IGoodsOperService;
import com.jinghangzz.shop.goods.service.IGoodsService;
import com.jinghangzz.shop.goods.util.ServiceCallableUtil;

/**
 * Oper的GoodsService
 * @author TeaBig
 */
@Service("goodsOperService")
public class GoodsOperServiceImpl extends BaseServiceImpl implements IGoodsOperService
{
	@Resource
	private IGoodsService goodsService;

	/**
	 * 参数就是我们说的文件夹
	 */
	@Override
	public List<AGoodsCate> findListCateTreeService(AGoodsCate currCate)
	{
		ConstatFinalUtil.SYS_LOGGER.info("==findListCateTreeService==");
		Map<String, Object> condMap = new HashMap<String, Object>();
		/* 存储结果 */
		List<AGoodsCate> goodsCateList = new ArrayList<AGoodsCate>();
		if(currCate != null)
		{
			/* 查询的是一个节点 */
			/* 指定一个分类 */
			this.findListCateTreeServiceUtil(currCate,0,goodsCateList);
			
			List<AGoodsCate> ancestorsCateList = new ArrayList<AGoodsCate>();
			/* 向上查询 */
			this.findListCateTreeServiceUpUtil(currCate,ancestorsCateList);
			/* List如何倒序 */
			Collections.reverse(ancestorsCateList);
			currCate.setAncestorsCateList(ancestorsCateList);
		}else
		{
			/* 查询的是整棵树
			 * ~把所有的一级节点查询出来;(parnetId=0);
			 *  */
			condMap.clear();
			condMap.put("parentId", "0");
			List<AGoodsCate> cateList = this.goodsService.findCondListGoodsCateService(null, condMap);
			/* 所有的一级节点循环 */
			for (Iterator iterator = cateList.iterator(); iterator.hasNext();)
			{
				AGoodsCate cateTemp = (AGoodsCate) iterator.next();
				this.findListCateTreeServiceUtil(cateTemp,0,goodsCateList);
				
				List<AGoodsCate> ancestorsCateList = new ArrayList<AGoodsCate>();
				/* 向上查询 */
				this.findListCateTreeServiceUpUtil(cateTemp,ancestorsCateList);
				Collections.reverse(ancestorsCateList);
				cateTemp.setAncestorsCateList(ancestorsCateList);
			}
		}
		return goodsCateList;
	}
	
	/**
	 * 递归的工具类
	 * 如果想在递归的方法中存储数据,有两种方法
	 * 	~返回值:只能有一个
	 * 	~形参:形参可以有多个,
	 * @param cate	当前类
	 * @return
	 */
	public void findListCateTreeServiceUtil(AGoodsCate cate,int level,List<AGoodsCate> goodsCateList)
	{
		/* sb:前导字符串 */
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < level; i++)
		{
			sb.append("|-->");
		}
		/*
		 * 即想以树形的结构显示,又想以平板形式显示
		 * (前导字符串|-->即想显示又不想显示);需求
		 * */
		//cate.setName(sb.toString() + cate.getName());
		cate.setTreeName(sb.toString() + cate.getName());
		goodsCateList.add(cate);
		//ConstatFinalUtil.SYS_LOGGER.info(sb.toString() + cate.getName());
		/* 判断一下它有木有子节点
		 * 如:cate就是电视
		 * 查看一下电视有哪些子节点;(合资品牌,互联网品牌,国产品牌)
		 * 因为合资品牌的parentid就电视的id;'
		 * select * from a_goods_cate where parentid = 电视.id
		 * 
		 * 当前分类有多个子分类:一对多;
		 * 当前分类只能一个父分类:多对一;
		 * 经常说的关联关系a和b是两个同不的类,今天我们见的分类:a和b是同一个类;
		 *  */
		List<AGoodsCate> childCateList = cate.getChildCateList() ;
		if(childCateList.size() > 0)
		{
			/* 非叶子节点 */
			cate.setLeafStatus(Byte.valueOf("0"));
			for (Iterator iterator = childCateList.iterator(); iterator.hasNext();)
			{
				AGoodsCate cateTemp = (AGoodsCate) iterator.next();
				/* 获取到第一个子节点 */
				findListCateTreeServiceUtil(cateTemp,level + 1,goodsCateList);
			}
		}else
		{
			/* 木有孩子,断后了;叶子节点 */
			cate.setLeafStatus(Byte.valueOf("1"));
		}
	}
	
	/**
	 * 向上找
	 * @param cate	当前类
	 * @return
	 */
	public void findListCateTreeServiceUpUtil(AGoodsCate cate,List<AGoodsCate> ancestorsCateList)
	{
		/*
		 * 即想以树形的结构显示,又想以平板形式显示
		 * (前导字符串|-->即想显示又不想显示);需求
		 * */
		//ConstatFinalUtil.SYS_LOGGER.info("==findListCateTreeServiceUpUtil==" + cate.getName());
		ancestorsCateList.add(cate);
		AGoodsCate parentCate = cate.getParentCate() ; 
		if(parentCate != null)
		{
			/* 如果有爸爸 */
			this.findListCateTreeServiceUpUtil(parentCate,ancestorsCateList);
		}
	}
	
	/**
	 * 最终目的是分页查询
	 */
	@Override
	public void operBatchSpiderGoodsService(AGoodsCate currCate)
	{
		SpiderUtil spiderUtil = new SpiderUtil();
		JSONObject outerTypeJSON = currCate.getOuterTypeJSON() ; 
		JSONObject jdOuterTypeJSON = outerTypeJSON.getJSONObject("jd");
		/* 分类id */
		String cate = jdOuterTypeJSON.getString("cateId"); 
		String sort = "" ;
		/* 抓取
		 * 先查询一次,目的就是为了获取总页数
		 *  */
		JSONObject resultJSON = spiderUtil.jdGoodsList(cate,sort,"1");
		
		if("0".equalsIgnoreCase(resultJSON.getString("code")))
		{
			/* 请求成功 */
			JSONObject dataResJSON = (JSONObject) resultJSON.get("data");
			int totalPage = dataResJSON.getIntValue("totalPage");
			ConstatFinalUtil.SYS_LOGGER.info("总页数:{}",totalPage);
			
			/* 循环 */
			/* for(int i = 1 ; i <= totalPage ; i ++) */
			/* 先抓取一页进行测试 */
			/* 总页数是:135页
			 * 10个人同时请求;
			 * 原理和分页特别像
			 * 总条数是:135;
			 * 共10页;
			 * 135 / 10 = 13 余数5:
			 * 这10个人,都分别请求的页数为(京东的爬虫)
			 *  */
			int totalThreadNum = 10 ; 
			PageInfoUtil pageInfoUtil = new PageInfoUtil();
			/* 总条数 */
			pageInfoUtil.setTotalRecord(totalPage);
			/* 要求:10个线程访问,就是10个人 */
			pageInfoUtil.setPageSize(totalPage / totalThreadNum );
			
			/* 多线程的容器 */
			List<Callable<Object>> callList = new ArrayList<Callable<Object>>();
			
			for(int i = 1 ; i <= pageInfoUtil.getTotalPage() ; i ++)
			{
				/* 设置当前页 */
				pageInfoUtil.setCurrentPage(i);
				/* 起始条数 */
				int stRecord = pageInfoUtil.getCurrentRecord();
				/* 结束条数 */
				int edRecord = pageInfoUtil.getCurrentRecord() + pageInfoUtil.getPageSize();
				if(pageInfoUtil.getTotalRecord() < edRecord)
				{
					edRecord = pageInfoUtil.getTotalRecord() ; 
				}
				ConstatFinalUtil.SYS_LOGGER.info("当前页:{},起始条数:{},结束条数:{},总条数:{},总页数:{}",
						pageInfoUtil.getCurrentPage(),stRecord, 
						edRecord,pageInfoUtil.getTotalRecord(),pageInfoUtil.getTotalPage());
				/* 创建一个 Callable*/
				ServiceCallableUtil serviceCallableUtil = new ServiceCallableUtil();
				serviceCallableUtil.setOperType("batchSpider");
				Map<String, Object> paramsMap = new HashMap<String, Object>();
				
				paramsMap.put("goodsOperService", this);
				paramsMap.put("currCate", currCate);
				paramsMap.put("stRecord", stRecord);
				paramsMap.put("edRecord", edRecord);
				
				serviceCallableUtil.setParamsMap(paramsMap);
				/* 准备启动多线程 */
				callList.add(serviceCallableUtil);
			}
			
			/* main方法等待多线程执行的结果 */
			ExecutorUtil.invokeAll(callList);
			
//			for(int i = 1 ; i <= 1 ; i ++)
//			{
//				operBatchSpiderGoodsServicePageUtil(currCate,i);
//			}
		}
	}
	
	/**
	 * 多线程分配任务;
	 * @param stRecord
	 * @param edRecord
	 */
	public void operBatchJdThread(AGoodsCate currCate,int stRecord,int edRecord)
	{
		ConstatFinalUtil.SYS_LOGGER.info("分类:{},stRecord:{},edRecord:{}",currCate.getName() ,stRecord,edRecord);
		for(int i = stRecord ; i < edRecord ; i ++)
		{
			operBatchSpiderGoodsServicePageUtil(currCate,i);
		}
	}

	/**
	 * 抓取指定页数的京东信息
	 * @param currCate
	 * @param i
	 */
	private void operBatchSpiderGoodsServicePageUtil(AGoodsCate currCate, int i)
	{
		Map<String, Object> condMap = new HashMap<String, Object>();
		ConstatFinalUtil.SYS_LOGGER.info("分类:{},当前页:{}",currCate.getName() , i);
		
		SpiderUtil spiderUtil = new SpiderUtil();
		JSONObject outerTypeJSON = currCate.getOuterTypeJSON() ; 
		JSONObject jdOuterTypeJSON = outerTypeJSON.getJSONObject("jd");
		/* 分类id */
		String cate = jdOuterTypeJSON.getString("cateId"); 
		String sort = "" ;
		/* 抓取
		 * 先查询一次,目的就是为了获取总页数
		 *  */
		JSONObject resultJSON = spiderUtil.jdGoodsList(cate,sort,i + "");
		
		Random random = new Random();
		if("0".equalsIgnoreCase(resultJSON.getString("code")))
		{
			/* 请求成功 */
			JSONObject dataResJSON = (JSONObject) resultJSON.get("data");
			JSONArray listArr = (JSONArray) dataResJSON.get("list");
			for (Iterator iterator = listArr.iterator(); iterator.hasNext();)
			{
				JSONObject listTemp = (JSONObject) iterator.next();
				try
				{
					/* 存在更新,不存在保存 */
					String goodsId = listTemp.getString("goodsId");
					boolean updateFlag = true ; 
					/* 根据京东的id查询 */
					condMap.clear();
					condMap.put("outerId", goodsId);
					condMap.put("outerType", "0");
					AGoods goods = this.goodsService.findOneGoodsService(condMap);
					if(goods == null)
					{
						/* 创建一个商品对象,保存到数据库里面 */
						goods = new AGoods();
						goods.setCreateTime(new Date());
						updateFlag = false ;
					}
					
					goods.setOuterType(Byte.valueOf("0"));
					goods.setCateId(currCate.getId());
					int brandId = random.nextInt(7) + 1 ;
					goods.setBrandId(brandId);
					String name = listTemp.getString("name") ;
					goods.setName(name);
					goods.setTitle(name);
					/* url:标题首字母的拼音;不能重复 */
					goods.setUrl(goodsId);
					goods.setPrice(listTemp.getDoubleValue("price"));
					/* 市场价 */
					double marketPrice = random.nextInt(5) + 1 + goods.getPrice();
					goods.setMarketPrice(marketPrice);
					goods.setImgs(listTemp.getString("imgPath"));
					/* 设置京东的id */
					goods.setOuterId(goodsId);
					/* 内容应该抓取详情页面 */
					goods.setContent(name);
					
					goods.setUpdateTime(new Date());
					goods.setPubTime(new Date());
					
					JSONObject resultDbJSON = new JSONObject();
					if(updateFlag)
					{
						/* 更新 */
						resultDbJSON = this.goodsService.updateOneGoodsService(goods);
					}else
					{
						/* 保存数据 */
						resultDbJSON = this.goodsService.saveOneGoodsService(goods);
					}
					ConstatFinalUtil.SYS_LOGGER.info("操作结果:{}",resultDbJSON.toJSONString());
				} catch (Exception e)
				{
					ConstatFinalUtil.SYS_LOGGER.error("出错了:",e);
				}
			}
		}
	}
}
